#pragma once
#include <codecvt>
#include <fstream>
#include <regex>
#include <string>

using std::string;
namespace hyperUtil {
inline bool isDigit(const string &str) {
  for (char c : str) {
    if (!std::isdigit(c)) {
      return false;
    }
  }
  return true;
}

inline bool isIpv4String(const std::string &s) {
  const std::regex ipregex(
      R"(^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)");
  std::cmatch m;
  return std::regex_match(s.c_str(), m, ipregex);
}

inline bool isPort(const string &str) {
  if (isDigit(str)) {
    auto port = atoi(str.c_str());
    if (port >= 1024 && port <= 65535)
      return true;
    return false;
  }

  return false;
}

inline int preNUm(const char byte) {
  unsigned char mask = 0x80;
  int num = 0;
  for (int i = 0; i < 8; i++) {
    if ((byte & mask) == mask) {
      mask = mask >> 1;
      num++;
    } else {
      break;
    }
  }
  return num;
}

inline bool is_str_utf8(const std::string &s) {
  int num = 0;
  int i = 0;
  auto len = s.length();
  auto data = s.data();
  while (i < len) {
    if ((data[i] & 0x80) == 0x00) {
      i++;
      continue;
    } else if ((num = preNUm(data[i])) > 2) {

      i++;
      for (int j = 0; j < num - 1; j++) {

        if ((data[i] & 0xc0) != 0x80) {
          return false;
        }
        i++;
      }
    } else {
      return false;
    }
  }
  return true;
}

inline bool is_str_gbk(const std::string &s) {
  size_t i = 0;
  const unsigned char *str = (const unsigned char *)s.c_str();
  auto length = s.length();
  while (i < length) {
    if (*(str + i) > 0x80) { // 中文字符
      if (i + 1 >= length || *(str + i + 1) < 0x40 || *(str + i + 1) > 0xFE) {
        return false; // 不是 gbk 编码
      } else {
        i += 2;
      }
    } else { // ascii 字符
      i++;
    }
  }

  return true; // 是 gbk 编码
}

// gbk 转utf-8

inline auto gb2312_to_utf8(std::string const &strGb2312)
    -> std::optional<std::string> {
  std::vector<wchar_t> buff(strGb2312.size());
#ifdef _MSC_VER
  std::locale loc("zh-CN");
#else
  std::locale loc("zh_CN.GB18030");
#endif
  wchar_t *pwszNext = nullptr;
  const char *pszNext = nullptr;
  mbstate_t state = {};
  int res = std::use_facet<std::codecvt<wchar_t, char, mbstate_t>>(loc).in(
      state, strGb2312.data(), strGb2312.data() + strGb2312.size(), pszNext,
      buff.data(), buff.data() + buff.size(), pwszNext);

  if (std::codecvt_base::ok == res) {
    std::wstring_convert<std::codecvt_utf8<wchar_t>> cutf8;
    return cutf8.to_bytes(std::wstring(buff.data(), pwszNext));
  }

  return std::nullopt;
}

inline auto transUTF8Str(const string &str) -> string {
  if (!is_str_utf8(str)) {
    auto utfStr = gb2312_to_utf8(str);
    if (utfStr)
      return *utfStr;
    return str;
  }

  return str;
}

inline bool isValidUTF8Character(const unsigned char *sequence, size_t length) {
  // 根据 UTF-8 编码规则，检查首字节是否符合 UTF-8 字符的规范
  if (length == 0)
    return false;

  if ((sequence[0] & 0x80) == 0x00) { // 单字节字符，高位比特为 0
    return true;
  } else if ((sequence[0] & 0xE0) == 0xC0 &&
             length >= 2) { // 双字节字符，高位比特为 110
    return (sequence[1] & 0xC0) == 0x80;
  } else if ((sequence[0] & 0xF0) == 0xE0 &&
             length >= 3) { // 三字节字符，高位比特为 1110
    return (sequence[1] & 0xC0) == 0x80 && (sequence[2] & 0xC0) == 0x80;
  } else if ((sequence[0] & 0xF8) == 0xF0 &&
             length >= 4) { // 四字节字符，高位比特为 11110
    return (sequence[1] & 0xC0) == 0x80 && (sequence[2] & 0xC0) == 0x80 &&
           (sequence[3] & 0xC0) == 0x80;
  }

  return false; // 非有效的 UTF-8 字符
}

inline void removeInvalidUtfByte(unsigned char bytes[], size_t size,
                                 std::vector<unsigned char> &vec) {

  for (size_t i = 0; i < size; /* Increment in the loop */) {
    if (bytes[i] == 0)
      break;
    // 计算下一个字符的长度
    size_t characterLength = 1;
    if (isValidUTF8Character(&bytes[i], 4)) {
      // 是有效的 UTF-8 字符，计算其长度
      if ((bytes[i] & 0x80) == 0x00)
        characterLength = 1;
      else if ((bytes[i] & 0xE0) == 0xC0)
        characterLength = 2;
      else if ((bytes[i] & 0xF0) == 0xE0)
        characterLength = 3;
      else if ((bytes[i] & 0xF8) == 0xF0)
        characterLength = 4;
    } else {
      // 非有效的 UTF-8 字符，可以根据需求进行处理，此处直接忽略非 UTF-8 字符
      i++;
      continue;
    }

    // 将有效 UTF-8 字符添加到过滤后的数据中
    vec.insert(vec.end(), &bytes[i], &bytes[i + characterLength]);

    // 移动到下一个字符
    i += characterLength;
  }
}

inline auto readFile(const string &fileName, string &strFile)
    -> std::optional<string> {
  std::ifstream file(fileName);

  if (!file.is_open()) {
    return "open file error, please check the file is exist or check file path";
  }

  file.seekg(0, std::ios::end);
  std::streampos length = file.tellg();
  file.seekg(0, std::ios::beg);

  char *buffer = new char[length];
  file.read(buffer, length);
  file.close();

  strFile = std::string(buffer, length);
  delete[] buffer;

  return std::nullopt;
}

} // namespace hyperUtil